// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:在kern中创建达尔文| |蜻蜓| | freebsd | | netbsd | | openbsd 

package syscall

import (
	"runtime"
	"unsafe"
)

var (
	freebsdConfArch       string // “机器$arch”行。freebsd 
	minRoutingSockaddrLen = rsaAlignOf(0)
)

// 将原始sockaddr的长度向上舍入，以便正确对齐。
func rsaAlignOf(salen int) int {
	salign := sizeofPtr
	if darwin64Bit {
		// 达尔文内核需要对
		// 路由设施进行32位对齐访问。
		salign = 4
	} else if netbsd32Bit {
		// NetBSD 6及更高版本的内核需要64位对齐的
		// 访问路由设施。
		salign = 8
	} else if runtime.GOOS == "freebsd" {
		// 就克恩而言。supported_archs=“amd64 i386”，
		// 我们需要知道底层内核的
		// 体系结构，因为路由
		// 设施的对齐是在内核构建时设置的。
		if freebsdConfArch == "amd64" {
			salign = 8
		}
	}
	if salen == 0 {
		return salign
	}
	return (salen + salign - 1) & ^(salign - 1)
}

// parseSockaddrLink将b解析为数据链路套接字地址。
func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) {
	if len(b) < 8 {
		return nil, EINVAL
	}
	sa, _, err := parseLinkLayerAddr(b[4:])
	if err != nil {
		return nil, err
	}
	rsa := (*RawSockaddrDatalink)(unsafe.Pointer(&b[0]))
	sa.Len = rsa.Len
	sa.Family = rsa.Family
	sa.Index = rsa.Index
	return sa, nil
}

// ParseLinkLayerADR以
// 传统的BSD内核形式将b解析为数据链路套接字地址。
func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) {
	// /编码如下所示：
	// /+--------------------------------------+
	// /|类型（1个八位字节）| 
	// /+--------------------------------------+
	// /|名称长度（1个八位字节）| 
	// /+----------------------------+
	// /|选择器长度（1个八位字节）| 
	// /+--------------------------------------+
	// /|数据（变量）| 
	// /+----------------------------+
	type linkLayerAddr struct {
		Type byte
		Nlen byte
		Alen byte
		Slen byte
	}
	lla := (*linkLayerAddr)(unsafe.Pointer(&b[0]))
	l := 4 + int(lla.Nlen) + int(lla.Alen) + int(lla.Slen)
	if len(b) < l {
		return nil, 0, EINVAL
	}
	b = b[4:]
	sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen}
	for i := 0; len(sa.Data) > i && i < l-4; i++ {
		sa.Data[i] = int8(b[i])
	}
	return sa, rsaAlignOf(l), nil
}

// 
func parseSockaddrInet(b []byte, family byte) (Sockaddr, error) {
	switch family {
	case AF_INET:
		if len(b) < SizeofSockaddrInet4 {
			return nil, EINVAL
		}
		rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
		return anyToSockaddr(rsa)
	case AF_INET6:
		if len(b) < SizeofSockaddrInet6 {
			return nil, EINVAL
		}
		rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
		return anyToSockaddr(rsa)
	default:
		return nil, EINVAL
	}
}

const (
	offsetofInet4 = int(unsafe.Offsetof(RawSockaddrInet4{}.Addr))
	offsetofInet6 = int(unsafe.Offsetof(RawSockaddrInet6{}.Addr))
)

// ParseNetworkLayerADR将b解析为传统BSD内核形式的internet套接字地址。
func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
	// 该编码看起来与NLRI编码类似。
	// /+---------------------------------------
	// |长度（1个八位字节）| 
	// /+---------------------------------------
	// /|地址前缀（变量）| 
	// /+--------------
	// 
	// 内核形式和NLRI 
	// 编码之间的区别是：
	// 
	// -内核形式的长度字段表示前缀
	// length（字节），而不是位
	// 
	// -在内核形式中，长度字段
	// 的零值并不意味着0.0.0.0/0或：：/0 
	// 
	// -内核窗体将前导字节添加到前缀字段
	// 以使<length，prefix>元组与
	// 路由消息边界
	l := int(rsaAlignOf(int(b[0])))
	if len(b) < l {
		return nil, EINVAL
	}
	// 不重新排序大小写表达式。
	// IPv6的case表达式必须放在第一位。
	switch {
	case b[0] == SizeofSockaddrInet6:
		sa := &SockaddrInet6{}
		copy(sa.Addr[:], b[offsetofInet6:])
		return sa, nil
	case family == AF_INET6:
		sa := &SockaddrInet6{}
		if l-1 < offsetofInet6 {
			copy(sa.Addr[:], b[1:l])
		} else {
			copy(sa.Addr[:], b[l-offsetofInet6:l])
		}
		return sa, nil
	case b[0] == SizeofSockaddrInet4:
		sa := &SockaddrInet4{}
		copy(sa.Addr[:], b[offsetofInet4:])
		return sa, nil
	default: // 一种旧的方式，AF_unsec或unknown意味着AF_INET 
		sa := &SockaddrInet4{}
		if l-1 < offsetofInet4 {
			copy(sa.Addr[:], b[1:l])
		} else {
			copy(sa.Addr[:], b[l-offsetofInet4:l])
		}
		return sa, nil
	}
}

// 路由返回路由信息库，称为RIB，
// 由网络设备信息、状态和
// 参数组成。
// 
// 不推荐：使用golang。改为org/x/net/route。
func RouteRIB(facility, param int) ([]byte, error) {
	mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
	// 查找大小。
	n := uintptr(0)
	if err := sysctl(mib, nil, &n, nil, 0); err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}
	tab := make([]byte, n)
	if err := sysctl(mib, &tab[0], &n, nil, 0); err != nil {
		return nil, err
	}
	return tab[:n], nil
}

// RoutingMessage表示路由消息。
// 
// 不推荐：使用golang。改为org/x/net/route。
type RoutingMessage interface {
	sockaddr() ([]Sockaddr, error)
}

const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))

type anyMessage struct {
	Msglen  uint16
	Version uint8
	Type    uint8
}

// RouteMessage表示包含路由
// 项的路由消息。
// 
// 不推荐：使用golang。改为org/x/net/route。
type RouteMessage struct {
	Header RtMsghdr
	Data   []byte
}

func (m *RouteMessage) sockaddr() ([]Sockaddr, error) {
	var sas [RTAX_MAX]Sockaddr
	b := m.Data[:]
	family := uint8(AF_UNSPEC)
	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
		if m.Header.Addrs&(1<<i) == 0 {
			continue
		}
		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
		switch rsa.Family {
		case AF_LINK:
			sa, err := parseSockaddrLink(b)
			if err != nil {
				return nil, err
			}
			sas[i] = sa
			b = b[rsaAlignOf(int(rsa.Len)):]
		case AF_INET, AF_INET6:
			sa, err := parseSockaddrInet(b, rsa.Family)
			if err != nil {
				return nil, err
			}
			sas[i] = sa
			b = b[rsaAlignOf(int(rsa.Len)):]
			family = rsa.Family
		default:
			sa, err := parseNetworkLayerAddr(b, family)
			if err != nil {
				return nil, err
			}
			sas[i] = sa
			b = b[rsaAlignOf(int(b[0])):]
		}
	}
	return sas[:], nil
}

// InterfaceMessage表示包含
// 网络接口条目的路由消息。
// 
// 不推荐：使用golang。改为org/x/net/route。
type InterfaceMessage struct {
	Header IfMsghdr
	Data   []byte
}

func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) {
	var sas [RTAX_MAX]Sockaddr
	if m.Header.Addrs&RTA_IFP == 0 {
		return nil, nil
	}
	sa, err := parseSockaddrLink(m.Data[:])
	if err != nil {
		return nil, err
	}
	sas[RTAX_IFP] = sa
	return sas[:], nil
}

// InterfaceAddrMessage表示包含
// 网络接口地址项的路由消息。
// 
// 不推荐：使用golang。改为org/x/net/route。
type InterfaceAddrMessage struct {
	Header IfaMsghdr
	Data   []byte
}

func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) {
	var sas [RTAX_MAX]Sockaddr
	b := m.Data[:]
	family := uint8(AF_UNSPEC)
	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
		if m.Header.Addrs&(1<<i) == 0 {
			continue
		}
		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
		switch rsa.Family {
		case AF_LINK:
			sa, err := parseSockaddrLink(b)
			if err != nil {
				return nil, err
			}
			sas[i] = sa
			b = b[rsaAlignOf(int(rsa.Len)):]
		case AF_INET, AF_INET6:
			sa, err := parseSockaddrInet(b, rsa.Family)
			if err != nil {
				return nil, err
			}
			sas[i] = sa
			b = b[rsaAlignOf(int(rsa.Len)):]
			family = rsa.Family
		default:
			sa, err := parseNetworkLayerAddr(b, family)
			if err != nil {
				return nil, err
			}
			sas[i] = sa
			b = b[rsaAlignOf(int(b[0])):]
		}
	}
	return sas[:], nil
}

// ParseRoutingMessage将b解析为路由消息，并返回包含路由消息接口的
// slice。
// 
// 不推荐：使用golang。改为org/x/net/route。
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
	nmsgs, nskips := 0, 0
	for len(b) >= anyMessageLen {
		nmsgs++
		any := (*anyMessage)(unsafe.Pointer(&b[0]))
		if any.Version != RTM_VERSION {
			b = b[any.Msglen:]
			continue
		}
		if m := any.toRoutingMessage(b); m == nil {
			nskips++
		} else {
			msgs = append(msgs, m)
		}
		b = b[any.Msglen:]
	}
	// 我们未能解析任何消息-版本不匹配？
	if nmsgs != len(msgs)+nskips {
		return nil, EINVAL
	}
	return msgs, nil
}

// ParseRoutingSockaddr将msg的有效负载解析为原始Sockaddr，
// 返回包含Sockaddr接口的切片。
// 
// 不推荐：使用golang。改为org/x/net/route。
func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) {
	sas, err := msg.sockaddr()
	if err != nil {
		return nil, err
	}
	return sas, nil
}
